import uuid
import hashlib
import secrets
from datetime import datetime
from typing import Any, Dict, List, Optional
import re

def generate_task_id() -> str:
    """生成任务ID"""
    return f"task_{uuid.uuid4().hex[:12]}"

def generate_execution_id() -> str:
    """生成执行ID"""
    return f"exec_{uuid.uuid4().hex[:12]}"

def generate_api_key() -> str:
    """生成API密钥"""
    return secrets.token_urlsafe(32)

def hash_string(text: str) -> str:
    """生成字符串哈希"""
    return hashlib.sha256(text.encode()).hexdigest()

def validate_url(url: str) -> bool:
    """验证URL格式"""
    url_pattern = re.compile(
        r'^https?://'  # http:// or https://
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|'  # domain...
        r'localhost|'  # localhost...
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # ...or ip
        r'(?::\d+)?'  # optional port
        r'(?:/?|[/?]\S+)$', re.IGNORECASE)
    
    return bool(url_pattern.match(url))

def validate_email(email: str) -> bool:
    """验证邮箱格式"""
    email_pattern = re.compile(r'^[^@]+@[^@]+\.[^@]+$')
    return bool(email_pattern.match(email))

def sanitize_filename(filename: str) -> str:
    """清理文件名"""
    # 移除或替换不安全的字符
    filename = re.sub(r'[<>:"/\\|?*]', '_', filename)
    # 限制长度
    if len(filename) > 255:
        filename = filename[:255]
    return filename

def format_file_size(size_bytes: int) -> str:
    """格式化文件大小"""
    if size_bytes == 0:
        return "0B"
    
    size_names = ["B", "KB", "MB", "GB", "TB"]
    i = 0
    while size_bytes >= 1024 and i < len(size_names) - 1:
        size_bytes /= 1024.0
        i += 1
    
    return f"{size_bytes:.1f}{size_names[i]}"

def format_duration(seconds: int) -> str:
    """格式化时长"""
    if seconds < 60:
        return f"{seconds}秒"
    elif seconds < 3600:
        minutes = seconds // 60
        remaining_seconds = seconds % 60
        return f"{minutes}分{remaining_seconds}秒"
    else:
        hours = seconds // 3600
        remaining_minutes = (seconds % 3600) // 60
        return f"{hours}小时{remaining_minutes}分钟"

def calculate_success_rate(total: int, errors: int) -> float:
    """计算成功率"""
    if total == 0:
        return 0.0
    return ((total - errors) / total) * 100

def parse_cron_expression(cron_expr: str) -> bool:
    """验证CRON表达式格式"""
    # 简单的CRON表达式验证
    if not cron_expr:
        return False
    
    parts = cron_expr.split()
    if len(parts) != 5:
        return False
    
    # 这里可以添加更详细的CRON表达式验证逻辑
    return True

def extract_domain(url: str) -> Optional[str]:
    """从URL中提取域名"""
    try:
        from urllib.parse import urlparse
        parsed = urlparse(url)
        return parsed.netloc
    except Exception:
        return None

def merge_dicts(dict1: Dict[str, Any], dict2: Dict[str, Any]) -> Dict[str, Any]:
    """合并字典"""
    result = dict1.copy()
    result.update(dict2)
    return result

def chunk_list(lst: List[Any], chunk_size: int) -> List[List[Any]]:
    """将列表分块"""
    return [lst[i:i + chunk_size] for i in range(0, len(lst), chunk_size)]

def safe_get(dictionary: Dict[str, Any], key: str, default: Any = None) -> Any:
    """安全获取字典值"""
    try:
        return dictionary.get(key, default)
    except (AttributeError, TypeError):
        return default

def timestamp_to_datetime(timestamp: float) -> datetime:
    """时间戳转换为datetime"""
    return datetime.fromtimestamp(timestamp)

def datetime_to_timestamp(dt: datetime) -> float:
    """datetime转换为时间戳"""
    return dt.timestamp()

class ErrorCode:
    """错误码常量"""
    # 通用错误
    INVALID_REQUEST = "INVALID_REQUEST"
    VALIDATION_ERROR = "VALIDATION_ERROR"
    RESOURCE_NOT_FOUND = "RESOURCE_NOT_FOUND"
    PERMISSION_DENIED = "PERMISSION_DENIED"
    
    # 任务相关错误
    TASK_NOT_FOUND = "TASK_NOT_FOUND"
    TASK_ALREADY_RUNNING = "TASK_ALREADY_RUNNING"
    TASK_CANNOT_START = "TASK_CANNOT_START"
    INVALID_TASK_CONFIG = "INVALID_TASK_CONFIG"
    
    # 用户相关错误
    USER_NOT_FOUND = "USER_NOT_FOUND"
    INVALID_CREDENTIALS = "INVALID_CREDENTIALS"
    USER_ALREADY_EXISTS = "USER_ALREADY_EXISTS"
    
    # 系统错误
    SYSTEM_OVERLOAD = "SYSTEM_OVERLOAD"
    DATABASE_ERROR = "DATABASE_ERROR"
    CRAWL4AI_ERROR = "CRAWL4AI_ERROR"
    QUEUE_FULL = "QUEUE_FULL"
